Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

38장. Java스럽게 작성한 Kotlin 개선하기

자바를 하다 코틀린으로 넘어오면
자기도 모르게 “자바처럼” 코드를 짜게 됩니다.

동작은 하지만
코틀린의 장점을 살리지 못한 코드입니다.

이 장에서는 흔한 “자바스러운 코틀린“을
“코틀린다운 코틀린“으로 바꾸는 법을 정리합니다.

지금까지 배운 내용을
“고치는 관점“에서 복습하는 장이기도 합니다.


38.1 Getter와 Setter를 그대로 옮기지 않기

자바 습관대로
게터/세터를 손으로 만드는 경우가 있습니다.

// 자바스러운 코틀린
class User {
    private var name: String = ""
    fun getName(): String = name
    fun setName(value: String) { name = value }
}

코틀린은 프로퍼티가
게터/세터를 자동으로 만들어 줍니다. (7장)

// 코틀린다운 코드
class User(var name: String)

한 줄이면 충분합니다.


38.2 불필요한 var 줄이기

습관적으로 var를 쓰는 경우가 많습니다.

// 개선 전
var total = 0
for (item in items) {
    total += item.price
}

대부분은 val로 바꿀 수 있습니다. (2·13장)

// 개선 후
val total = items.sumOf { it.price }

값이 한 번 정해지면 바뀌지 않으니
val이 더 안전합니다.

일단 val, 꼭 필요할 때만 var.


38.3 불필요한 !! 없애기

!!는 “null이면 터뜨려라“는 뜻입니다. (5장)
남발하면 위험합니다.

// 위험한 코드
val name = user!!.name!!

대부분 엘비스 연산자나 safe call로
더 안전하게 바꿀 수 있습니다.

// 개선 후
val name = user?.name ?: "이름 없음"

!!가 보이면
“정말 여기서 터져도 되는가“를 되물어야 합니다.


38.4 반복문을 Collection 함수로 바꾸기

for 반복문으로 목록을 가공하는 코드가 많습니다.

// 개선 전
val names = mutableListOf<String>()
for (user in users) {
    if (user.age >= 20) {
        names.add(user.name)
    }
}

컬렉션 함수를 쓰면
의도가 한눈에 드러납니다. (13장)

// 개선 후
val names = users
    .filter { it.age >= 20 }
    .map { it.name }

“거른다 → 변환한다“는 흐름이
그대로 코드가 됩니다.


38.5 Utility Class를 Extension Function으로 바꾸기

자바에서는 StringUtils 같은
유틸리티 클래스를 만들곤 했습니다.

// 자바스러운 코틀린
object StringUtils {
    fun isValidEmail(value: String): Boolean = value.contains("@")
}

StringUtils.isValidEmail(email)

코틀린에서는 확장 함수가 더 자연스럽습니다. (17장)

// 코틀린다운 코드
fun String.isValidEmail(): Boolean = contains("@")

email.isValidEmail()

값이 앞에 오니
문장처럼 읽힙니다.


38.6 과도한 Scope Function 줄이기

스코프 함수(15장)는 편하지만
너무 중첩하면 오히려 읽기 어렵습니다.

// 과한 예
user?.let { u ->
    u.address?.let { a ->
        a.city?.let { c ->
            println(c)
        }
    }
}

safe call 체인으로 펴는 편이 낫습니다.

// 개선 후
val city = user?.address?.city
if (city != null) println(city)

코틀린다운 코드가
코틀린 문법을 많이 쓴 코드는 아닙니다.


38.7 불필요한 상속 제거하기

상속을 습관적으로 쓰는 경우가 있습니다.
하지만 코틀린 클래스는 기본이 final입니다. (8장)

상속보다

  • 인터페이스로 역할을 나누거나 (8장)
  • 위임(by)을 쓰는 편이 (19장) 더 유연할 때가 많습니다.

“이건 저것의 한 종류다“가 아니면
상속을 의심해 보세요.


38.8 Null과 Exception을 명확하게 표현하기

실패를 어정쩡하게 표현하지 말고
의도를 분명히 드러냅니다. (24장)

// 모호한 코드
fun find(id: Long): User {
    return repository.findById(id)!!   // 없으면 그냥 터짐
}

“없을 수 있음“인지 “없으면 오류“인지
명확히 구분합니다.

// 없을 수 있음 → nullable
fun findOrNull(id: Long): User? = repository.findById(id)

// 없으면 오류 → 명확한 예외
fun getById(id: Long): User =
    repository.findById(id) ?: throw UserNotFoundException(id)

이름과 타입만 봐도
동작이 예상되게 만드는 것이 좋습니다.


38장을 마치며

이 장에서 우리는 다음을 정리했습니다.

  • 손수 만든 게터/세터 대신 프로퍼티 쓰기
  • 불필요한 var!! 줄이기
  • 반복문을 컬렉션 함수로 바꾸기
  • 유틸리티 클래스를 확장 함수로 바꾸기
  • 과한 스코프 함수와 상속 줄이기
  • null과 예외로 실패를 명확히 표현하기

다음 장은 이 책의 마지막입니다.
백엔드 개발자가 기억해야 할 핵심을 정리합니다.